import { Link } from '@brillout/docpress'
import { UiFrameworkExtension } from '../../components'
import { TableStyle } from './TableStyle'

You can define meta tags inside `<head>` by using following settings.

<TableStyle>
Setting | Sets
-- | --
<Link href="/title">`title`</Link> | <ul><li>[`<title>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title)</li> <li>[`<meta property="og:title">`](https://ogp.me/#metadata:~:text=every%20page%20are%3A-,og%3Atitle,-%2D%20The%20title%20of)</li></ul>
<Link href="/description">`description`</Link> | <ul><li>[`<meta name="description">`](https://moz.com/learn/seo/meta-description)</li> <li>[`<meta property="og:description">`](https://ogp.me/#optional:~:text=accompany%20this%20object.-,og%3Adescription,-%2D%20A%20one%20to)</li></ul>
<Link href="/image">`image`</Link> | <ul> <li>[`<meta property="og:image">`](https://ahrefs.com/blog/open-graph-meta-tags/#:~:text=8%20simple%20steps.%22%20/%3E-,%3Cmeta%20property%3D%22og%3Aimage%22,-content%3D%22https%3A//ahrefs) (preview image upon URL sharing)</li> <li>[`<meta name="twitter:card" content="summary_large_image">`](https://ogp.me/#optional:~:text=accompany%20this%20object.-,og%3Adescription,-%2D%20A%20one%20to)</li></ul>
<Link href="/viewport">`viewport`</Link> | <ul><li>[`<meta name="viewport">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag)</li></ul>
<Link href="/Head">`Head`</Link> | Other `<head>` tags such as: <ul> <li>[`<link rel="icon">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) (favicon)</li> <li>[`<link rel="apple-touch-icon">`](https://stackoverflow.com/questions/20440512/why-use-link-rel-apple-touch-icon-image-src/20440627#20440627) (mobile icon)</li> <li>[`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)</li> <li>...</li> </ul>
</TableStyle>

> You can set these settings dynamically:
> - Inside your `+data` hook, by using the <Link href="/useConfig">`useConfig()` hook</Link>.
> - Inside your components, by using the <Link href="/useConfig#config-head">`<Config>` and `<Head>` components</Link>.

> See <Link href="/settings#html" /> for other HTML settings (most notably `bodyAttributes`, `htmlAttributes`, `lang`).

> These settings are provided by <UiFrameworkExtension name />. If you don't use <UiFrameworkExtension name noLink /> then see <Link href="/head-manual" />.

> You can <Link href="#custom-settings">create your own custom settings</Link>.


## Defaults

You can set defaults (that pages can override).

```js
// pages/+config.js

import image from './previewImage.jpg'

export default {
  // Default <title>
  title: 'Awesome Rockets',
  // Default <meta name="description">
  description: 'We deliver payload to space',
  // Default <meta property="og:image">
  image
}
```

## Page-specific

You can set values for one page or a group of pages (potentially overriding defaults).

```js
// pages/starship/+config.js

export default {
  title: 'Rocket: Starship',
  description: 'The Starship is the largest rocket ever built.'
}
```

> See: <Link href="/config#inheritance"/>


## `Head` setting

For other `<head>` tags, you can use the `Head` setting:

```jsx
// pages/+Head.jsx or
// pages/+Head.vue

import favicon from './favicon.svg'

// Applies to all pages (cannot be overridden)
export function Head() {
  // All pages share the same favicon
  return <>
    <link rel="icon" href={favicon} type="image/svg+xml">
  </>
}
```

> Unlike `title`/`description`/`image`, the `Head` setting is cumulative which means that `pages/+Head.js` cannot be overridden, see <Link href="/Head#cumulative"></Link>.


## Data

You can set `<head>` tags based on <Link href="/data-fetching">fetched data</Link>:

```js
// pages/rocket/starship/+data.js

export async function data() {
  const data = await sql.run(
    'SELECT { title, description } FROM rockets WHERE name = "starship";'
  )
  return data
}
```
```ts
// pages/rocket/starship/+title.ts

import type { PageContext } from 'vike/types'
import type { Data } from './+data'

// Overrides the default <title>
export default (pageContext: PageContext<Data>) => pageContext.data.title
```

You can define the logic once and apply it to all pages:

```js
// pages/+title.js

// Applies to all pages: if a page fetches data and data.title is defined then
// use it to set the page's title.
export default (pageContext) => pageContext.data?.title || 'Some Default Title'
```

You can use:
- <Link href="/useData">`useData()`</Link> and <Link href="/usePageContext">`usePageContext()`</Link> inside the `+Head` setting, see <Link href="/Head#using-data" />.
- <Link href="/useConfig">The `useConfig()` hook</Link> to set `<head>` tags inside your `+data` hook (or any Vike hook).
- <Link href="/useConfig#config-head">The `<Config>` and `<Head>` components</Link> to set `<head>` tags inside your components.
  > The `<Config>` and `<Head>` components are particularly relevant when using integrations that enable data-fetching components,
  > such as [`vike-react-query`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-query#readme) and [`vike-react-apollo`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-apollo#readme).

> The settings `description` and `image` can also access the <Link href="/pageContext">`pageContext`</Link> like this.


## Custom settings

You can create your own custom settings.

For example, let's create a new setting `dynamicFavicon` that allows different favicons to be set for different pages.

### Setting creation

```js
// pages/+config.js

export default {
  meta: {
    dynamicFavicon: {
      env: { server: true, client: true }
    }
  }
}
```
> See: <Link href="/meta" />

```js
// pages/+Head.jsx

import { usePageContext } from 'vike-react/usePageContext' // or vike-vue / vike-solid

export default () => {
  const pageContext = usePageContext()
  const { dynamicFavicon } = pageContext.config
  return <>
    { dynamicFavicon && <link rel="icon" href={dynamicFavicon}> }
  <>
}
```
```js
// pages/+onAfterRenderClient.js

export default (pageContext) => {
  if (!pageContext.isHydration) {
    const { dynamicFavicon } = pageContext.config
    updateFavicon(dynamicFavicon)
  }
}

// https://stackoverflow.com/questions/260857/changing-website-favicon-dynamically
function updateFavicon(dynamicFavicon) {
  let link = document.querySelector("link[rel~='icon']")
  if (!dynamicFavicon) {
    if (link) document.head.removeChild(link)
    return
  }
  if (!link) {
    link = document.createElement('link')
    link.rel = 'icon'
    document.head.appendChild(link)
  }
  link.href = dynamicFavicon
}
```

For TypeScript users:

```ts
// pages/+config.js

declare global {
  namespace Vike {
    interface Config {
      dynamicFavicon?: string
    }
  }
}
```

> See: <Link href="/meta#typescript" />

### Setting usage

```js
// pages/+config.js

import favicon from './favicon.svg'

export {
  // Default favicon
  dynamicFavicon: favicon
}
```

```js
// pages/premium-members/+config.js

import favicon from './favicon.svg'

export {
  // Favicon for /premium-members
  dynamicFavicon: favicon
}
```

## Internationalization

Example of internationalizing (i18n) `<head>` tags:

```jsx
// pages/+Head.js
// Environment: server

export { Head }

import { usePageContext } from 'vike-react/usePageContext' // or 'vike-vue' / 'vike-solid'

function Head() {
  const pageContext = usePageContext()
  const description = pageContext.locale === 'de-DE' ?
    'Wir liefern zum Weltall.' :
    'We deliver payload to space.'
  return <>
    <meta name="description" content={description}>
  </>
}
```
```js
// pages/+title.js
// Environment: server, client

export function title(pageContext) {
  const title = pageContext.locale === 'de-DE' ?
    'AwesomeRockets | Das Weltall Unternehmen' :
    'AwesomeRockets | The space company'
  return title
}
```

See also:
 - <Link href="/i18n" />
 - <Link href="/usePageContext" />


## Markdown

See <Link href="/markdown#metadata" />.


## See also

- [Blog post "My current HTML boilerplate" showcasing and explaining a common boilerplate](https://www.matuzo.at/blog/html-boilerplate/)
- <Link href="/settings#html" doNotInferSectionTitle />
- <Link href="/head-manual" />
